package org.xinhe.perf.data.gatling.vega.convertor;


import org.xinhe.perf.data.gatling.collector.result.ApiTestResult;
import org.xinhe.perf.data.gatling.collector.result.Statistics;
import org.xinhe.perf.data.gatling.vega.dto.*;
import org.xinhe.perf.data.gatling.collector.result.GatlingStatistics;

import java.util.*;

/**
 * <p>Title: TestingResultVegaConvertor</p>
 * <p>Date: 2018/9/30 </p>
 * <p>Description: </p>
 *
 * @author sunxinhe
 */
public class TestingResultVegaConvertor {

    public static VegaLiteReport convert(List<GatlingStatistics> gatlingStatistics) {
        VegaLiteReport report = new VegaLiteReport();

        report.set$schema("https://vega.github.io/schema/vega-lite/v2.json");

        // 构建数据
        List<Map<String, Object>> qpsList = new LinkedList<>();
        List<Map<String, Object>> costRatioList = new LinkedList<>();
        List<Map<String, Object>> responseTimeList = new LinkedList<>();
        buildValue(gatlingStatistics, qpsList, costRatioList, responseTimeList);



        LinkedList<Vconcat> vconcats = new LinkedList<>();
        // qps && response time
        Vconcat qpsAndRespTimevconcat = new Vconcat();
        qpsAndRespTimevconcat.setWidth(600);


        ArrayList<Layer> layers = new ArrayList<>();
        // qps
        Layer qpsLayer = new Layer();
        qpsLayer.setMark("line");
        qpsLayer.setEncoding(getQpsEncoding());
        Data qpsData = new Data();
        qpsData.setValues(qpsList);
        qpsLayer.setData(qpsData);
        layers.add(qpsLayer);

        Layer respTimeLayer = new Layer();
        respTimeLayer.setMark("line");
        respTimeLayer.setEncoding(getResponseTimeEncoding());
        Data respTimeData = new Data();
        respTimeData.setValues(responseTimeList);
        respTimeLayer.setData(respTimeData);
        layers.add(respTimeLayer);

        Resolve resolve = new Resolve();
        Scale scale = new Scale();
        scale.setY("independent");
        resolve.setScale(scale);
        qpsAndRespTimevconcat.setResolve(resolve);

        qpsAndRespTimevconcat.setLayer(layers);
        vconcats.add(qpsAndRespTimevconcat);

        // time cost ratio
        Vconcat costRatioVconcat = new Vconcat();
        costRatioVconcat.setWidth(600);
        costRatioVconcat.setMark("bar");
        costRatioVconcat.setEncoding(getCostRatioEncoding());
        Data costRatioData = new Data();
        costRatioData.setValues(costRatioList);
        costRatioVconcat.setData(costRatioData);
        vconcats.add(costRatioVconcat);


        report.setVconcat(vconcats);

        return report;
    }

    private static void buildValue(List<GatlingStatistics> gatlingStatistics,
                                   List<Map<String, Object>> qpsList,
                                   List<Map<String, Object>> costRatioList,
                                   List<Map<String, Object>> responseTimeList) {
        for (GatlingStatistics gatlingStatistic : gatlingStatistics) {
            Map<String, ApiTestResult> contents = gatlingStatistic.getContents();

            if (contents == null && contents.size() <= 0) {
                continue;
            }
            Map.Entry<String, ApiTestResult> resultEntry = contents.entrySet().iterator().next();

            ApiTestResult apiTestResult = resultEntry.getValue();
            Integer concurrent = getConcurrentNumFromName(apiTestResult.getName());
            Statistics statistics = apiTestResult.getStats();

            // qps
            buildQpsValues(qpsList, concurrent, statistics);

            // resp time
            buildResponseTimeValues(responseTimeList, concurrent, statistics);

            // time cost ratio
            buildTimeCostRatioValues(costRatioList, concurrent, "TimeCostRatio", statistics.getGroup1().getPercentage(), "TimeCost0800", statistics.getGroup2().getPercentage(), "TimeCost1200", statistics.getGroup3().getPercentage(), "TimeCost9999", statistics.getGroup4().getPercentage(), "TimeCostFFFF");

        }
    }

    private static void buildQpsValues(List<Map<String, Object>> qpsList, Integer concurrent, Statistics statistics) {
        Map<String, Object> qpsValue = new LinkedHashMap<>();
        qpsValue.put("Concurrent", concurrent);
        qpsValue.put("Qps", statistics.getMeanNumberOfRequestsPerSecond().getTotal());
        qpsValue.put("title", "Qps");
        qpsList.add(qpsValue);
    }

    private static void buildResponseTimeValues(List<Map<String, Object>> responseTimeList, Integer concurrent, Statistics statistics) {
        Map<String, Object> responseTime50 = new LinkedHashMap<>();
        responseTime50.put("Concurrent", concurrent);
        responseTime50.put("ResponseTime", statistics.getPercentiles1().getTotal());
        responseTime50.put("title", "ResponseTime50");
        responseTimeList.add(responseTime50);

        Map<String, Object> responseTime75 = new LinkedHashMap<>();
        responseTime75.put("Concurrent", concurrent);
        responseTime75.put("ResponseTime", statistics.getPercentiles2().getTotal());
        responseTime75.put("title", "ResponseTime75");
        responseTimeList.add(responseTime75);

        Map<String, Object> responseTime95 = new LinkedHashMap<>();
        responseTime95.put("Concurrent", concurrent);
        responseTime95.put("ResponseTime", statistics.getPercentiles3().getTotal());
        responseTime95.put("title", "ResponseTime95");
        responseTimeList.add(responseTime95);

        Map<String, Object> responseTime99 = new LinkedHashMap<>();
        responseTime99.put("Concurrent", concurrent);
        responseTime99.put("ResponseTime", statistics.getPercentiles4().getTotal());
        responseTime99.put("title", "ResponseTime99");
        responseTimeList.add(responseTime99);

        Map<String, Object> responseTimeMean = new LinkedHashMap<>();
        responseTimeMean.put("Concurrent", concurrent);
        responseTimeMean.put("ResponseTime", statistics.getMeanResponseTime().getTotal());
        responseTimeMean.put("title", "ResponseTimeMean");
        responseTimeList.add(responseTimeMean);
    }

    private static void buildTimeCostRatioValues(List<Map<String, Object>> costRatioList, Integer concurrent, String timeCostRatio, int percentage, String timeCost0800, int percentage2, String timeCost12002, int percentage3, String timeCost9999, int percentage4, String timeCostFFFF) {
//        Map<String, Object> timeCost800 = new LinkedHashMap<>();
//        timeCost800.put("Concurrent", concurrent);
//        timeCost800.put(timeCostRatio, percentage);
//        timeCost800.put("title", timeCost0800);
//        costRatioList.add(timeCost800);

        Map<String, Object> timeCost1200 = new LinkedHashMap<>();
        timeCost1200.put("Concurrent", concurrent);
        timeCost1200.put(timeCostRatio, percentage2);
        timeCost1200.put("title", timeCost12002);
        costRatioList.add(timeCost1200);

        Map<String, Object> timeOut = new LinkedHashMap<>();
        timeOut.put("Concurrent", concurrent);
        timeOut.put(timeCostRatio, percentage3);
        timeOut.put("title", timeCost9999);
        costRatioList.add(timeOut);

        Map<String, Object> failed = new LinkedHashMap<>();
        failed.put("Concurrent", concurrent);
        failed.put(timeCostRatio, percentage4);
        failed.put("title", timeCostFFFF);
        costRatioList.add(failed);
    }

    private static Integer getConcurrentNumFromName(String name) {
        //"Compute-Api-50"
        Integer ret = null;

        if (name != null) {
            String[] split = name.split("-");
            if (split != null && split.length >= 3) {
                String concurrentStr = split[2];
                ret = Integer.valueOf(concurrentStr);
            }
        }
        return ret;
    }

    private static Encoding getQpsEncoding() {
        Encoding encoding = new Encoding();
        Axis x = new Axis();
        x.setField("Concurrent");
        x.setType("quantitative");
        encoding.setX(x);

        Axis y = new Axis();
        y.setField("Qps");
        y.setType("quantitative");
        encoding.setY(y);

        Color color = new Color();
        color.setField("title");
        color.setType("nominal");
        encoding.setColor(color);
        return encoding;
    }

    private static Encoding getResponseTimeEncoding() {
        Encoding encoding = new Encoding();
        Axis x = new Axis();
        x.setField("Concurrent");
        x.setType("quantitative");
        encoding.setX(x);

        Axis y = new Axis();
        y.setField("ResponseTime");
        y.setType("quantitative");
        encoding.setY(y);

        Color color = new Color();
        color.setField("title");
        color.setType("nominal");
        encoding.setColor(color);
        return encoding;
    }

    public static Encoding getCostRatioEncoding() {
        Encoding encoding = new Encoding();
        Axis x = new Axis();
        x.setField("Concurrent");
        x.setType("ordinal");
        encoding.setX(x);

        Axis y = new Axis();
        y.setField("TimeCostRatio");
        y.setType("quantitative");
//        y.setStack("normalize");

        encoding.setY(y);

        Color color = new Color();
        color.setField("title");
        color.setType("nominal");
        encoding.setColor(color);
        return encoding;
    }
}
